/*
	Copyright 2009 Benjamin Vedder	vedder87@gmail.com
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */

package com.google.code.retrobox.editor.tiles;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.List;

import javax.swing.*;
import javax.swing.border.BevelBorder;

import com.google.code.retrobox.editor.commons.Tools;
import com.google.code.retrobox.editor.dataCollections.TileData;


public class SingleTileRenderer extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static int 	PIX_W = 15,
						PIX_H = 15;
	
	private TileData tile;
	private TileEditor tileEditor = null;
	
	private List<ActionListener> listeners = new LinkedList<ActionListener>();
	
	private PixelPanel[] pixels;
	
	class PixelPanel extends JPanel {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private Boolean mouseInside = false;
		//private PixelPanel self = this;
		private TileEditor tileEditor = null;
		
		private Color	hoverColor = Color.black, 
						bgColor = Color.black;
		
		public PixelPanel(TileEditor e) {
			super();
			this.tileEditor = e;
			
			addMouseListener(new java.awt.event.MouseListener() {
				public void mouseEntered(java.awt.event.MouseEvent evt) {
					mouseInside = true;
					
					if (tileEditor != null) {
						hoverColor = tileEditor.getCurrentColor();
						
						if (evt.isShiftDown()) {
							bgColor = hoverColor;
						}
						
						setBackground(hoverColor);
						repaint();
					}
				}

				public void mouseExited(java.awt.event.MouseEvent evt) {
					mouseInside = false;
					
					if (tileEditor != null) {
						if (evt.isShiftDown()) {
							bgColor = hoverColor;
						}
						
						if (bgColor.getRGB()  != getBackground().getRGB()) {
							setBackground(bgColor);
							repaint();
						}
					}
				}


				public void mousePressed(MouseEvent arg0) {
					if (arg0.isPopupTrigger() && tileEditor != null) {
						tileEditor.setCurrentColor(bgColor);
					}
				}

				public void mouseReleased(MouseEvent arg0) {
					if (tileEditor != null && arg0.getButton() == MouseEvent.BUTTON1 && mouseInside) {
						bgColor = hoverColor;
						
						if (bgColor.getRGB()  != getBackground().getRGB()) {
							setBackground(bgColor);
							repaint();
						}
					}
					
					if (arg0.isPopupTrigger() && tileEditor != null) {
						tileEditor.setCurrentColor(bgColor);
					}
					
				}

				public void mouseClicked(MouseEvent arg0) {
					
				}

			});
		}
		
		/**
		 * Use setBg to set the background color when tileEditor is not null.
		 */
		public void setBg(Color c) {
			bgColor = c;
			setBackground(c);
		}
		
		public boolean isMouseInside() {
			return mouseInside;
		}
	}
	
	
	public SingleTileRenderer(TileData tile, TileEditor e) {
		this.tile = tile;
		this.tileEditor = e;
		init();
	}
	
	private void init() {
		setOpaque(true);
		
		setLayout(new GridLayout(Tile.HEIGHT, Tile.WIDTH));
		pixels = new PixelPanel[Tile.WIDTH * Tile.HEIGHT];
		
		putPixels();
		
		for (PixelPanel element: pixels) {
			add(element);
			element.setBorder(BorderFactory.createEtchedBorder());
			element.setOpaque(true);
		}
	}

	public void putPixels() {
		for (int i = 0;i < (Tile.WIDTH * Tile.HEIGHT);i++) {
			Color c;
			int d;
			if ((i % 2) != 0) {
				d = tile.pixels[i / 2] & 0x000F;
			} else {
				d = tile.pixels[i / 2] >>> 4;
			}
			
			c = Tools.getColor(d);
			
			PixelPanel tmp = new PixelPanel(tileEditor);
			tmp.setPreferredSize(new Dimension(PIX_W, PIX_H));
			tmp.setOpaque(true);
			tmp.setBg(c);
			pixels[i] = tmp;
		}
	}
	
	public void flipTileX(){
		final int BPC = 4;
		char[] buffer = new char[tile.pixels.length];
		int length = tile.pixels.length / BPC;
		for(int t=0;t < length;t++){
			buffer[t*BPC] =  swapNibble(tile.pixels[t*BPC+3]);
			buffer[t*BPC+1] =  swapNibble(tile.pixels[t*BPC+2]);
			buffer[t*BPC+2] =  swapNibble(tile.pixels[t*BPC+1]);
			buffer[t*BPC+3] =  swapNibble(tile.pixels[t*BPC]);
		}
		tile.pixels = buffer;
		updatePixels();		
	}
	
	private char swapNibble(char value){
		return (char) (((value & 0x0F) << 4) | (value >> 4));
	}
	
	public void flipTileY(){
		final int BPC = 4;
		char[] buffer = new char[tile.pixels.length];
		int length = tile.pixels.length / BPC;
		for(int t=0;t < length;t++){
			buffer[t*BPC] =  tile.pixels[(8-1-t)*BPC];
			buffer[t*BPC+1] =  tile.pixels[(8-1-t)*BPC+1];
			buffer[t*BPC+2] =  tile.pixels[(8-1-t)*BPC+2];
			buffer[t*BPC+3] =  tile.pixels[(8-1-t)*BPC+3];
		}
		tile.pixels = buffer;
		updatePixels();
	}
	
	public TileData getTileData() {
		return tile;
	}
	
	public void updatePixels() {
		int i = 0;
		for (PixelPanel element: pixels) {
			Color c;
			int d;
			if ((i % 2) != 0) {
				d = tile.pixels[i / 2] & 0x000F;
			} else {
				d = tile.pixels[i / 2] >>> 4;
			}
			
			c = Tools.getColor(d);
			element.setBg(c);
			i++;
		}
	}
	
	public void setTile(TileData t) {
		tile = t;
		updatePixels();
		for (ActionListener element: listeners) {
			element.actionPerformed(new ActionEvent(this, 0, "New tile set"));
		}
	}
	

	public void addActionListener(ActionListener w) {
		listeners.add(w);
	}
	
	public void saveData() {
		char[] pix = new char[(Tile.WIDTH * Tile.HEIGHT) / 2];
		
		int ind = 0;
		for (PixelPanel element: pixels) {
			if (ind % 2 == 0) {
				pix[ind / 2] = (char)((Tools.getColorIndex(element.getBackground())<<4));
			} else {
				pix[ind / 2] = (char)(pix[ind / 2] | Tools.getColorIndex(element.getBackground()));
			}
			ind++;
		}
		
		tile.pixels = pix;
	}
	
	public char[] copyPixelData() {
		char[] pix = new char[(Tile.WIDTH * Tile.HEIGHT) / 2];
		
		int ind = 0;
		for (PixelPanel element: pixels) {
			if (ind % 2 == 0) {
				pix[ind / 2] = (char)((Tools.getColorIndex(element.getBackground())<<4));
			} else {
				pix[ind / 2] = (char)(pix[ind / 2] | Tools.getColorIndex(element.getBackground()));
			}
			ind++;
		}
		
		return pix;
	}	
	
	public void pastePixelData(char[] pix){
		tile.pixels = pix.clone();
		updatePixels();
	}
	
}





